/*
Q900控制协议
2021.3.2
BG1JT
Q群:742774905 欢迎交流
*/




#include <Arduino.h>
#include <SoftwareSerial.h>
#include "Q900.h"


// 默认通讯端口
SoftwareSerial rigCat(11, 10); // rx,tx



Q900::Q900(){ } 

/****** SETUP ********/

// 设置端口
void Q900::setSerial()
{
  SoftwareSerial rigCat(11, 10);
}
/*
 * 初始化端口
 * baud:传输速率
*/
void Q900::begin(unsigned long baud)
{
  rigCat.begin(baud);
}
/*
 * 初始化端口
 * baud:传输速率
*/
void Q900::end()
{
  rigCat.end();
}


/*
 * 同步电台数据
*/
void Q900::SynRadioData(){

  byte data[]={0x00};  
  singleCmd(CAT_INFO_GET,data,9);
  ClreaBtSerial();
  sendRadioData(9);

  byte dataLen=getRadioData();
  if(dataLen<=0)return;
  
  TX=radioBuff[1];
  if(TX==1)
  {
    POWER=radioBuff[23]-128;
    SMETER=0;
    byte SAAVal=radioBuff[24];
    if(SAAVal>=ADU_R_VALUE)
    {
      //ADU
      SAA_TYPE=ADU_R_VALUE;
      SAAVal-=ADU_R_VALUE;
      
    }
    else if(SAAVal>=ALC_R_VALUE)
    {
      //ALC
      SAA_TYPE=ALC_R_VALUE;
      SAAVal-=ALC_R_VALUE;
    }
    else
    {
      //SWR
      SAA_TYPE=0;
    }
    SAA_VALUE=SAAVal;
  }
  else
  {
    VA_MODE=radioBuff[2];
    VB_MODE=radioBuff[3];
    VA_FREQ=HexToLong(radioBuff[4],radioBuff[5],radioBuff[6],radioBuff[7]);
  
    VB_FREQ=HexToLong(radioBuff[8],radioBuff[9],radioBuff[10],radioBuff[11]);
  
    A_B_MODE=radioBuff[12];
        
    switch(radioBuff[13])
    {
      case 0:
        NR_ON=NB_ON=0;
        break;
      case 1:
        NR_ON=1;
        NB_ON=0;
        break;
      case 2:
        NR_ON=0;
        NB_ON=1;
        break;     
    }
  
    RIT=radioBuff[14];
    XIT=radioBuff[15];
    FILTER=radioBuff[16];
    SPECTRNMU=radioBuff[17];
    VOLTAGE=radioBuff[18];
    //UTCTime=String(radioBuff[19])+":"+String(radioBuff[20])+":"+String(radioBuff[21]);
    //BT=(int(1&radioBuff[22])>0);
    //GPS=(int(2&radioBuff[22])>0);
    //LORA=(int(4&radioBuff[22])>0);
    //COMPASS=(int(8&radioBuff[22])>0);  
    TUNE=(int(16&radioBuff[22])>0);
    PLEVER=(int(32&radioBuff[22])>0);
      
     //接收
    SMETER=radioBuff[23];
    POWER=0;
    SAA_VALUE=0;
  }
}

/*设置电台频率*/
void Q900::SetFrequency(){
  
  unsigned char f_data[4];  
  FerqToHEXArray(VA_FREQ,f_data);

  byte _data[8]; 
    
  _data[0]=f_data[0];
  _data[1]=f_data[1];
  _data[2]=f_data[2];
  _data[3]=f_data[3];
  

  

  memset(f_data, 0x00,4);   
  FerqToHEXArray(VB_FREQ,f_data);
  
  _data[4]=f_data[0];
  _data[5]=f_data[1];
  _data[6]=f_data[2];
  _data[7]=f_data[3];
  
  
  singleCmd(CAT_FREQ_SET,_data,16);

 
  //ClreaBtSerial();
  sendRadioData(16);
  
  byte dataLen=getRadioData();
  ClreaBtSerial();
  /*if(dataLen<=0)return 0;
  else return 1;*/
  
}
//获得频谱数据
void Q900::GetSPEC(){
  byte _data[0]; 
  singleCmd(CAT_SPEC_GET,_data,8);
  sendRadioData(8);
  byte ct=0;
 
  //memset(_data, 0x00,164);  
   while (rigCat.available() < 1 && ct<=250) {  ct+=1;delay(10); }
  
}
/*获得串口数据*/
byte Q900::GetSSByte(){
  //rigCat.flush();
  return rigCat.read();
  
}
 
/*
void Q900::Ptt(bool ptt){
    
  byte data[]={0x00};  
  singleCmd(CAT_PPT_SET,data,9);
 
  //sendRadioData(9);
  //short dataLen=getRadioData();
}*/

/*
 * 发送电台协议数据
 * len:数据字节长度
*/
void Q900::sendRadioData(short len){
  //Serial.println("send");
  for (byte i=0; i<len; i++)
  {
    rigCat.write(cmdDataBUF[i]);
    //Serial.println(cmdDataBUF[i],HEX);        // 调试输出
    delay(CAT_DELAY);
  }
}


/*
 * 发送电台协议数据
 * len:数据字节长度
*/
void Q900::sendRadioDataBySerial(){

    for(byte i=0;i<4;i++)
    {
      rigCat.write(CAT_HEAD);          
      //delay(CAT_DELAY);
    }
    byte len=Serial.read();
    rigCat.write(len); 
    //delay(CAT_DELAY);
        
    while(len>0)
    {       
      //byte t=Serial.read();
      rigCat.write(Serial.read()); 
      len-=1;
      //delay(CAT_DELAY);
    }
    delay(250);
    ClreaSerial();
    ClreaBtSerial();
    
}



/*
 * 强制获得电台数据
 * 返回:接收到的数据长度,如不完整返回0
*/
byte Q900::getRadioData()
{
  
  //unsigned long  startTime = millis();
  byte ct=0;
  while (rigCat.available() < 1 && ct<=250) {  ct+=1;delay(5); }
  byte dataLen=0;
  
  if(rigCat.available())
  {              
    for (byte i=0; i<5; i++)
    {   
      if(i==4)
      {
        dataLen=rigCat.read();
      }
      else{
        rigCat.read();
      }
      //delay(10);      
    }
    if(dataLen>0)
    {
       memset(radioBuff, 0x00,MAX_BUF_SIZE); 
       byte i=0;
       while (rigCat.available())
       {
          radioBuff[i] = rigCat.read();
          //delay(10);
          i+=1;
       } 
       if(i!=dataLen)  dataLen=0;              
    }
  }
   
  ClreaBtSerial();  
  return dataLen;
}

/*
 * 生成协议数据
 * cmd:操作协议
 * data:发送数据
 * dataLen:数据长度,总长度头4+协议1+包长1+数据长度+CRC长度2
*/
void Q900::singleCmd(byte cmd,byte *data,byte dataLen)
{     
  
   memset(cmdDataBUF, 0x00,dataLen);      
  
   cmdDataBUF[0]=CAT_HEAD;
   cmdDataBUF[1]=CAT_HEAD;
   cmdDataBUF[2]=CAT_HEAD;
   cmdDataBUF[3]=CAT_HEAD;
      
   cmdDataBUF[4]=dataLen-5;//除包头,含CRC长
   cmdDataBUF[5]=cmd;  

   byte cmdLen=dataLen-8;//包头5+操作1+CRC2
   byte crcLen=cmdLen+2;
   
   char crcData[crcLen];
   crcData[0]=cmdDataBUF[4];
   crcData[1]=cmd;

   for(byte i=0;i<cmdLen;i++)
   {    
      crcData[i+2]=data[i];
      cmdDataBUF[i+6]=data[i];
   }  
     
   unsigned short cv=CRC16Check(crcData,crcLen);
  
   unsigned char dest[2];    
   IntToHEXArray(cv,dest);
   
   cmdDataBUF[dataLen-2]=dest[0];
   cmdDataBUF[dataLen-1]=dest[1];   
}




/*串口输出数据*/
void Q900::PrintSerialData(String str){
  rigCat.print(str);
}


//读取串口数据
String Q900::ReadSerialData(){

  //unsigned long startTime = millis();
  byte ct=0;
  while (rigCat.available() < 1 && ct<=250) {  ct+=1;delay(20); }
    
  if(rigCat.available())
  {
    String myString="";
    
    while (rigCat.available()) 
    {       
        myString += char(rigCat.read()); 
        //delay(2);
    } 
    //myString.replace("\r\n","");
    //Serial.println("READ:"+myString);
    return myString;
  }
  else{
    return "";
  }  
}


//清除串口数据
void Q900::ClreaSerial(){
  while(Serial.available() > 0)Serial.read();
  //Serial.flush();
}

//清除串口数据
void Q900::ClreaBtSerial(){
  while(rigCat.available() > 0)rigCat.read();
  //rigCat.flush();
}

/*
* 函数名称: CRC16Check
* 输 入: buf 要校验的数据;
* len 要校验的数据的长度
* 输 出: 校验值
* 功能描述: CRC16 循环冗余校验
* 备注：校验模式为 CRC16/CCITT-FALSE，注意变量类型
*/
unsigned int Q900::CRC16Check(unsigned char *buf, unsigned char len)
{
   unsigned char i, j;
   unsigned int uncrcReg = 0xFFFF;
   unsigned int uncur;
   for (i = 0; i < len; i++)
   {
      uncur = buf[i] << 8;
      for (j = 0; j < 8; j++)
      {
        if ((int)(uncrcReg ^ uncur) < 0)
        {
          uncrcReg = (uncrcReg << 1) ^ 0x1021;
        }
        else
        {
          uncrcReg <<= 1;
        }
        uncur <<= 1;
      }
   }
   return uncrcReg;
}


void Q900::FerqToHEXArray(unsigned long num, byte *dest)
{  
   String hex=String(num,HEX);
   hex.toUpperCase();
   
   byte len=8-hex.length();
   
   if(len==1)
   {hex="0"+hex;}
    else if(len==2)
   {hex="00"+hex;}
   else if(len==3)
   {hex="000"+hex;}
   else if(len==4)
   {hex="0000"+hex;}
   else if(len==5)
   {hex="00000"+hex;}
   
   char buf[hex.length()+1] ;
   hex.toCharArray(buf,hex.length()+1);
   AsciiToHex(buf, dest, strlen(buf));
  
}

/*
 * 数字转HEX数组
 * Num:无限定符长整型数字
 * dest:指针引用数组
 * len:指定补齐位长,0不指定
*/
void Q900::IntToHEXArray(unsigned int num, uint8_t *dest)
{  
   String hex=String(num,HEX);
   hex.toUpperCase();
   byte len=4-hex.length();
   if(len==1)
   {hex="0"+hex;}
    else if(len==2)
   {hex="00"+hex;}
   else if(len==3)
   {hex="000"+hex;}

   char buf[hex.length()+1] ;
   hex.toCharArray(buf,hex.length()+1);
   AsciiToHex(buf, dest, strlen(buf));
}

/*
void Q900::IntToHEXArray(unsigned int num, uint8_t *dest)
{  
   String hex=String(num,HEX);
   hex.toUpperCase();
   char buf[hex.length()+1] ;
   hex.toCharArray(buf,hex.length()+1);
   AsciiToHex(buf, dest, strlen(buf));
}*/

String Q900::Byte2HEXStr(byte dt)
{
   String tmp=String(dt,HEX);    
   if(tmp.length()<=1)tmp="0"+tmp;
   return tmp;
}

unsigned long Q900::HexToLong(byte D1,byte D2,byte D3,byte D4)
{ 
   String hex=Byte2HEXStr(D1);
   hex+=Byte2HEXStr(D2);   
   hex+=Byte2HEXStr(D3); 
   hex+=Byte2HEXStr(D4);  
   
   hex.toUpperCase();
  
   char buf[hex.length()+1] ;
   hex.toCharArray(buf,hex.length()+1);
   
   unsigned long rt=0;
   rt = strtol(buf, NULL, 16);   
    
   return rt;
}



void Q900::AsciiToHex(char *src, uint8_t *dest, byte len)
{
    int dh, dl;  // 16进制的高4位和低4位
    char ch, cl; //字符串的高位和低位
    byte i;
    /*if (src == NULL || dest == NULL)    {            
            return;
    }*/
    /*if (len < 1)
    {            
            return;
    }*/
    for (i = 0; i < len; i++)
    {
            ch = src[2 * i];
            cl = src[2 * i + 1];
            dh = ch - '0';
            if (dh > 9)
            {
                    dh = ch - 'A' + 10;   //lowtocap可以用库函数toupper
            }
            dl = cl - '0';
            if (dl > 9)
            {
                    dl = cl - 'A' + 10;   //lowtocap可以用库函数toupper
            }
            dest[i] = dh * 16 + dl;
    }
    if (len % 2 > 0) //字符串个数为奇数
    {
            dest[len / 2] = src[len - 1] - '0';
            if (dest[len / 2] > 9)
            {
                    dest[len / 2] = src[len - 1] - 'A' + 10;
            }
    }
}
